/*
 *    Canol's Movie Archiver - A cross-platform movie archivement program
 *    Copyright (C) 2008  Canol "ZuLuuuuuu" Gokel
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 2 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License along
 *    with this program; if not, write to the Free Software Foundation, Inc.,
 *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

using GLib;
using Gtk;

public class Movie : GLib.Object {
    public string name;
    public int cd_dvd_no;
    public bool subtitle;
    public int resolution_width;
    public int resolution_height;
    public string fps;
}

public class MovieArchiver : Window {
    public List<Movie> movies;
    
    private TreeView tree_view_main;

    enum COLUMNS {
        NAME,
        CD_DVD_NO,
        SUBTITLE,
        RESOLUTION_WIDTH,
        RESOLUTION_HEIGHT,
        FPS,
        COLUMN_NUMBER
    }
    
    construct {
        movies = new List<Movie> ();
        this.read_movie_data ();
        
        this.title = "Canol's Movie Archiver";
        this.set_size_request (500, 300);
        this.set_position (Gtk.WindowPosition.CENTER);

        tree_view_main = new TreeView ();
        tree_view_main.row_activated += (tree_view_main) => {
            this.row_activated (tree_view_main);
        };
        tree_view_main.set_rules_hint (true);
        this.setup_tree_view_main (tree_view_main);
        this.destroy += Gtk.main_quit;

        var accel_group_file = new AccelGroup ();
        var accel_group_edit = new AccelGroup ();
        var accel_group_help = new AccelGroup ();

        this.add_accel_group (accel_group_file);
        this.add_accel_group (accel_group_edit);
        this.add_accel_group (accel_group_help);

        var menu_bar_main = new MenuBar ();
        var menu_item_file = new MenuItem.with_label ("File");
        var menu_item_edit = new MenuItem.with_label ("Edit");
        var menu_item_help = new MenuItem.with_label ("Help");

        menu_bar_main.append (menu_item_file);
        menu_bar_main.append (menu_item_edit);
        menu_bar_main.append (menu_item_help);

        var menu_file = new Menu ();
        menu_file.set_accel_group (accel_group_file);
        var menu_edit = new Menu ();
        menu_file.set_accel_group (accel_group_edit);
        var menu_help = new Menu ();
        menu_file.set_accel_group (accel_group_edit);

        var menu_item_add_new_movie = new ImageMenuItem.from_stock(STOCK_ADD, null);
        menu_item_add_new_movie.activate += (menu_item_add_new_movie) => {
            this.movie_operations ("add_new_movie", tree_view_main);
        };
        menu_item_add_new_movie.add_accelerator ("activate", accel_group_file, Gdk.keyval_from_name("A"), Gdk.ModifierType.CONTROL_MASK, Gtk.AccelFlags.VISIBLE);
        var menu_item_save = new ImageMenuItem.from_stock(STOCK_SAVE, null);
        menu_item_save.activate += this.save;
        menu_item_save.add_accelerator ("activate", accel_group_file, Gdk.keyval_from_name("S"), Gdk.ModifierType.CONTROL_MASK, Gtk.AccelFlags.VISIBLE);
        var menu_item_quit = new ImageMenuItem.from_stock(STOCK_QUIT, null);
        menu_item_quit.activate += Gtk.main_quit;
        menu_item_quit.add_accelerator ("activate", accel_group_file, Gdk.keyval_from_name("Q"), Gdk.ModifierType.CONTROL_MASK, Gtk.AccelFlags.VISIBLE);

        menu_file.append (menu_item_add_new_movie);
        menu_file.append (menu_item_save);
        menu_file.append (menu_item_quit);

        var menu_item_edit_movie = new ImageMenuItem.from_stock(STOCK_EDIT, null);
        menu_item_edit_movie.activate += (menu_item_edit_movie) => {
            this.movie_operations ("edit_movie", tree_view_main);
        };
        menu_item_edit_movie.add_accelerator ("activate", accel_group_edit, Gdk.keyval_from_name("E"), Gdk.ModifierType.CONTROL_MASK, Gtk.AccelFlags.VISIBLE);
        var menu_item_delete_movie = new ImageMenuItem.from_stock(STOCK_DELETE, null);
        menu_item_delete_movie.activate += this.delete_movie;
        menu_item_delete_movie.add_accelerator ("activate", accel_group_edit, Gdk.keyval_from_name("Delete"), 0, Gtk.AccelFlags.VISIBLE);

        menu_edit.append (menu_item_edit_movie);
        menu_edit.append (menu_item_delete_movie);

        var menu_item_about = new ImageMenuItem.with_mnemonic("A_bout");
        menu_item_about.set_image (new Image.from_stock (STOCK_ABOUT, Gtk.IconSize.MENU));
        menu_item_about.activate += this.show_dialog_about;
        menu_item_about.add_accelerator ("activate", accel_group_edit, Gdk.keyval_from_name("B"), Gdk.ModifierType.CONTROL_MASK, Gtk.AccelFlags.VISIBLE);

        menu_help.append (menu_item_about);

        menu_item_file.set_submenu (menu_file);
        menu_item_edit.set_submenu (menu_edit);
        menu_item_help.set_submenu (menu_help);

        var temp = new VBox (false, 0);
        temp.pack_start (menu_bar_main, false, false, 0);

        var scrolled_window_main = new ScrolledWindow (null, null);
        scrolled_window_main.set_policy (Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC);
        
        scrolled_window_main.add (tree_view_main);
        temp.pack_start_defaults (scrolled_window_main);
        this.add (temp);
    }
    
    public void delete_movie () {
        ListStore tree_model_movies;
        TreeIter tree_iterator;
        TreeSelection tree_selection_movies;
        
        tree_selection_movies = tree_view_main.get_selection ();
        tree_selection_movies.get_selected (out tree_model_movies, out tree_iterator);
        
        tree_model_movies.remove (tree_iterator);
        this.title = "Canol's Movie Archiver *";
    }

    public void go_to_web_site(Gtk.AboutDialog dialog_about, string link) {
        try {
            show_uri(null, link, Gdk.CURRENT_TIME);
        } catch (GLib.Error error) {
            stdout.printf("Error: %s\n", error.message);            
        }
    }

    public void movie_operations (string action, TreeView tree_view_main) {
        Dialog dialog_operation;
        ListStore tree_model_movies;
        TreeIter tree_iterator;
        TreeSelection tree_selection_movies;
        
        Movie movie_data = new Movie ();
        
        if (action == "add_new_movie") {
            tree_model_movies = (ListStore) tree_view_main.get_model ();
        } else {
            tree_selection_movies = tree_view_main.get_selection ();
            tree_selection_movies.get_selected (out tree_model_movies, out tree_iterator);
            
            tree_model_movies.get (tree_iterator, COLUMNS.NAME, out movie_data.name, COLUMNS.CD_DVD_NO, out movie_data.cd_dvd_no, COLUMNS.SUBTITLE, out movie_data.subtitle, COLUMNS.RESOLUTION_WIDTH, out movie_data.resolution_width, COLUMNS.RESOLUTION_HEIGHT, out movie_data.resolution_height, COLUMNS.FPS, out movie_data.fps, -1);
        }
        
        if (action == "add_new_movie") {
            dialog_operation = new Dialog.with_buttons("Add New Movie", null, Gtk.DialogFlags.MODAL,
                                                       "Add", Gtk.ResponseType.OK,
                                                       "Cancel", Gtk.ResponseType.REJECT,
                                                       null);
        } else {
            dialog_operation = new Dialog.with_buttons("Edit Movie", null, Gtk.DialogFlags.MODAL,
                                                       "Ok", Gtk.ResponseType.OK,
                                                       "Cancel", Gtk.ResponseType.REJECT,
                                                       null);
        }
        
        dialog_operation.set_default_response (Gtk.ResponseType.OK);
        dialog_operation.set_position (Gtk.WindowPosition.CENTER);
        dialog_operation.set_border_width (3);

        var table_movie_operation = new Table (2, 6, false);
        table_movie_operation.set_row_spacings (3);
        table_movie_operation.set_col_spacings (3);
        
        var label_name = new Label ("Movie Name:");
        label_name.set_alignment (0, (float) 0.5);
        
        var entry_name = new Entry ();
        entry_name.set_activates_default (true);
        if (action == "edit_movie") {
            entry_name.set_text (movie_data.name);
        };
        
        table_movie_operation.attach (label_name, 0, 1, 0, 1, Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK, 0, 0);
        table_movie_operation.attach (entry_name, 1, 2, 0, 1, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK, 0, 0);

        var label_cd_dvd_no = new Label ("CD/DVD No:");
        label_cd_dvd_no.set_alignment (0, (float) 0.5);
        
        var entry_cd_dvd_no = new Entry ();
        entry_cd_dvd_no.set_activates_default (true);
        if (action == "edit_movie") {
            entry_cd_dvd_no.set_text (movie_data.cd_dvd_no.to_string ());
        };
        
        table_movie_operation.attach (label_cd_dvd_no, 0, 1, 1, 2, Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK, 0, 0);
        table_movie_operation.attach (entry_cd_dvd_no, 1, 2, 1, 2, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK, 0, 0);

        var label_subtitle = new Label ("Subtitle:");
        label_subtitle.set_alignment (0, (float) 0.5);
        
        var check_button_subtitle = new CheckButton ();
        if (action == "edit_movie") {
            check_button_subtitle.set_active (movie_data.subtitle);
        };
        
        table_movie_operation.attach (label_subtitle, 0, 1, 2, 3, Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK, 0, 0);
        table_movie_operation.attach (check_button_subtitle, 1, 2, 2, 3, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK, 0, 0);

        var label_width = new Label ("Width:");
        label_width.set_alignment (0, (float) 0.5);
        
        var entry_width = new Entry ();
        entry_width.set_activates_default (true);
        if (action == "edit_movie") {
            entry_width.set_text (movie_data.resolution_width.to_string ());
        };
        
        table_movie_operation.attach (label_width, 0, 1, 3, 4, Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK, 0, 0);
        table_movie_operation.attach (entry_width, 1, 2, 3, 4, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK, 0, 0);

        var label_height = new Label ("Height:");
        label_height.set_alignment (0, (float) 0.5);
        
        var entry_height = new Entry ();
        entry_height.set_activates_default (true);
        if (action == "edit_movie") {
            entry_height.set_text (movie_data.resolution_height.to_string ());
        };
        
        table_movie_operation.attach (label_height, 0, 1, 4, 5, Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK, 0, 0);
        table_movie_operation.attach (entry_height, 1, 2, 4, 5, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK, 0, 0);

        var label_fps = new Label ("FPS:");
        label_fps.set_alignment (0, (float) 0.5);
        
        var combo_box_entry_fps = new ComboBoxEntry.text ();
        combo_box_entry_fps.append_text ("-");
        combo_box_entry_fps.append_text ("23.976");
        combo_box_entry_fps.append_text ("25");
        combo_box_entry_fps.append_text ("29.97");
        if (action == "edit_movie") {
            if (movie_data.fps == "-") {
                combo_box_entry_fps.set_active (0);
            } else if (movie_data.fps == "23.976" || movie_data.fps == "23.9" || movie_data.fps == "23.97" || movie_data.fps == "23.98" || movie_data.fps == "24") {
                combo_box_entry_fps.set_active (1);
            } else if (movie_data.fps == "25") {
                combo_box_entry_fps.set_active (2);
            } else if (movie_data.fps == "29.97" || movie_data.fps == "29.9" || movie_data.fps == "30") {
                combo_box_entry_fps.set_active (3);
            } else {
                if (movie_data.fps.to_double () < 23.976) {
                    combo_box_entry_fps.insert_text (1, movie_data.fps);
                    combo_box_entry_fps.set_active (1);
                } else if (movie_data.fps.to_double () > 23.976 && movie_data.fps.to_double () < 25) {
                    combo_box_entry_fps.insert_text (2, movie_data.fps);
                    combo_box_entry_fps.set_active (2);
                } else if (movie_data.fps.to_double () > 25 && movie_data.fps.to_double () < 29.97) {
                    combo_box_entry_fps.insert_text (3, movie_data.fps);
                    combo_box_entry_fps.set_active (3);
                } else if (movie_data.fps.to_double () > 29.97) {
                    combo_box_entry_fps.append_text (movie_data.fps);
                    combo_box_entry_fps.set_active (4);
                }
            };
        } else {
            combo_box_entry_fps.set_active (0);
        };

        table_movie_operation.attach (label_fps, 0, 1, 5, 6, Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK, 0, 0);
        table_movie_operation.attach (combo_box_entry_fps, 1, 2, 5, 6, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK, 0, 0);

        dialog_operation.vbox.pack_start_defaults (table_movie_operation);

        dialog_operation.show_all ();
        
        int choice;
        
        while ((choice = dialog_operation.run ()) != Gtk.ResponseType.REJECT) {
            if (entry_name.get_text () == "") {
                var message_dialog_error = new MessageDialog (dialog_operation, Gtk.DialogFlags.MODAL,
                                                              Gtk.MessageType.ERROR, Gtk.ButtonsType.OK,
                                                              "You cannot leave \"Movie Name\" field empty.");
                message_dialog_error.set_title ("Error");
                message_dialog_error.run ();
                message_dialog_error.destroy ();
            } else {
                if (entry_cd_dvd_no.get_text () == "") {
                    entry_cd_dvd_no.set_text ("0");
                };
                if (entry_width.get_text () == "") {
                    entry_width.set_text ("0");
                };
                if (entry_height.get_text () == "") {
                    entry_height.set_text ("0");
                };
                if (combo_box_entry_fps.get_active_text () == "" || combo_box_entry_fps.get_active_text () == "0") {
                    combo_box_entry_fps.set_active (0);
                };
                                
                if (action == "add_new_movie") {
                    tree_model_movies.append (out tree_iterator);
                    tree_model_movies.set (tree_iterator, COLUMNS.NAME, entry_name.get_text (), COLUMNS.CD_DVD_NO, entry_cd_dvd_no.get_text ().to_int (), COLUMNS.SUBTITLE, check_button_subtitle.get_active (), COLUMNS.RESOLUTION_WIDTH, entry_width.get_text ().to_int (), COLUMNS.RESOLUTION_HEIGHT, entry_height.get_text ().to_int (), COLUMNS.FPS, combo_box_entry_fps.get_active_text (), -1);
                } else {
                    tree_selection_movies.get_selected (out tree_model_movies, out tree_iterator);
                    tree_model_movies.set (tree_iterator, COLUMNS.NAME, entry_name.get_text (), COLUMNS.CD_DVD_NO, entry_cd_dvd_no.get_text ().to_int (), COLUMNS.SUBTITLE, check_button_subtitle.get_active (), COLUMNS.RESOLUTION_WIDTH, entry_width.get_text ().to_int (), COLUMNS.RESOLUTION_HEIGHT, entry_height.get_text ().to_int (), COLUMNS.FPS, combo_box_entry_fps.get_active_text (), -1);
                };
                dialog_operation.destroy ();
                this.title = "Canol's Movie Archiver *";
                break;
            };
        };
        dialog_operation.destroy ();
    }

    public void read_movie_data () {
        string content;
        string[] all_movie_data;

        try {
            FileUtils.get_contents("movies.txt", out content);
        } catch (FileError error) {
            stdout.printf("Error: %s\n", error.message);
        }
        
        all_movie_data = content.strip ().split("\n");

        foreach (string movie_data in all_movie_data) {
            string[] current_movie_data;
            
            current_movie_data = movie_data.strip ().split("\t");

            Movie new_movie = new Movie ();

            new_movie.name = current_movie_data[0].strip ();
            new_movie.cd_dvd_no = current_movie_data[1].to_int ();
            if (current_movie_data[2] == "0")
                new_movie.subtitle = false;
            else
                new_movie.subtitle = true;
            new_movie.resolution_width = current_movie_data[3].to_int ();
            new_movie.resolution_height = current_movie_data[4].to_int ();
            new_movie.fps = current_movie_data[5].strip ();

            this.movies.append (new_movie);
        };
    }

    public void row_activated (TreeView tree_view_main) {
        
        movie_operations ("edit_movie", tree_view_main);
    }

    public void save () {
        string content = "";
        Movie movie = new Movie ();
        ListStore tree_model_movies;
        TreeIter tree_iterator;
        
        tree_model_movies = (ListStore) tree_view_main.get_model ();
        tree_model_movies.get_iter_first (out tree_iterator);
        
        do {
            tree_model_movies.get (tree_iterator, COLUMNS.NAME, out movie.name, COLUMNS.CD_DVD_NO, out movie.cd_dvd_no, COLUMNS.SUBTITLE, out movie.subtitle, COLUMNS.RESOLUTION_WIDTH, out movie.resolution_width, COLUMNS.RESOLUTION_HEIGHT, out movie.resolution_height, COLUMNS.FPS, out movie.fps, -1);
            content += movie.name + "\t" + movie.cd_dvd_no.to_string () + "\t" + (movie.subtitle ? "1" : "0") + "\t" + movie.resolution_width.to_string () + "\t" + movie.resolution_height.to_string () + "\t" + movie.fps + "\n";
        } while (tree_model_movies.iter_next (ref tree_iterator));
        
        try {
            FileUtils.set_contents("movies.txt", content);
        } catch (FileError error) {
            stdout.printf("Error: %s\n", error.message);
        }

        this.title = "Canol's Movie Archiver";
    }

    public void setup_tree_view_main (Gtk.TreeView tree_view) {
        var list_store = new Gtk.ListStore(COLUMNS.COLUMN_NUMBER, typeof(string), typeof(int), typeof(bool), typeof(int), typeof(int), typeof(string));
        tree_view.set_model(list_store);

        CellRenderer cell_renderer;

        cell_renderer = new Gtk.CellRendererText ();
        tree_view.insert_column_with_attributes (-1, "Name", cell_renderer, "text", COLUMNS.NAME, null);
        tree_view.get_column (COLUMNS.NAME).set_expand (true);
        tree_view.get_column (COLUMNS.NAME).set_resizable (true);

        cell_renderer = new Gtk.CellRendererText ();
        cell_renderer.set ("xalign", 0.5);
        tree_view.insert_column_with_attributes (-1, "CD/DVD", cell_renderer, "text", COLUMNS.CD_DVD_NO, null);
        tree_view.get_column (COLUMNS.CD_DVD_NO).set ("alignment", 0.5);
        tree_view.get_column (COLUMNS.CD_DVD_NO).set_resizable (true);

        cell_renderer = new Gtk.CellRendererToggle ();
        cell_renderer.set ("xalign", 0.5);
        tree_view.insert_column_with_attributes (-1, "Sub", cell_renderer, "active", COLUMNS.SUBTITLE, null);
        tree_view.get_column (COLUMNS.SUBTITLE).set ("alignment", 0.5);
        tree_view.get_column (COLUMNS.SUBTITLE).set_resizable (true);

        cell_renderer = new Gtk.CellRendererText ();
        cell_renderer.set ("xalign", 0.5);
        tree_view.insert_column_with_attributes (-1, "Width", cell_renderer, "text", COLUMNS.RESOLUTION_WIDTH, null);
        tree_view.get_column (COLUMNS.RESOLUTION_WIDTH).set ("alignment", 0.5);
        tree_view.get_column (COLUMNS.RESOLUTION_WIDTH).set_resizable (true);

        cell_renderer = new Gtk.CellRendererText ();
        cell_renderer.set ("xalign", 0.5);
        tree_view.insert_column_with_attributes (-1, "Height", cell_renderer, "text", COLUMNS.RESOLUTION_HEIGHT, null);
        tree_view.get_column (COLUMNS.RESOLUTION_HEIGHT).set ("alignment", 0.5);
        tree_view.get_column (COLUMNS.RESOLUTION_HEIGHT).set_resizable (true);

        cell_renderer = new Gtk.CellRendererText ();
        cell_renderer.set ("xalign", 0.5);
        tree_view.insert_column_with_attributes (-1, "FPS", cell_renderer, "text", COLUMNS.FPS, null);
        tree_view.get_column (COLUMNS.FPS).set ("alignment", 0.5);
        tree_view.get_column (COLUMNS.FPS).set_resizable (true);

        list_store.set_sort_func (COLUMNS.NAME, this.sort_movies);
        list_store.set_sort_column_id (COLUMNS.NAME, Gtk.SortType.ASCENDING);

        Gtk.TreeIter iter;

        foreach (Movie movie in movies) {
            list_store.append (out iter);
            list_store.set (iter, COLUMNS.NAME, movie.name, COLUMNS.CD_DVD_NO, movie.cd_dvd_no, COLUMNS.SUBTITLE, movie.subtitle, COLUMNS.RESOLUTION_WIDTH, movie.resolution_width, COLUMNS.RESOLUTION_HEIGHT, movie.resolution_height, COLUMNS.FPS, movie.fps, -1);
        }

        tree_view.get_column (COLUMNS.NAME).set ("sizing", Gtk.TreeViewColumnSizing.FIXED);
        tree_view.get_column (COLUMNS.NAME).set ("fixed-width", 100);
    }

    public void show_dialog_about () {
        string license;

        Gdk.Pixbuf logo;
        
        try {
            logo = new Gdk.Pixbuf.from_file ("icon.png");
        } catch (GLib.Error error) {
            stdout.printf ("Error: %s\n", error.message);
        }

        try {
            FileUtils.get_contents("LICENSE", out license);
        } catch (FileError error) {
            stdout.printf("Error: %s\n", error.message);
        }

        var dialog_about = new AboutDialog ();
        dialog_about.set_position (Gtk.WindowPosition.CENTER);

        AboutDialog.set_url_hook (go_to_web_site, null);
        
        dialog_about.set_program_name ("Canol's Movie Archiver");
        dialog_about.set_version ("0.6");
        dialog_about.set_copyright ("(c) 2008 Canol Gokel");
        dialog_about.set_comments ("A movie archive management program.");
        dialog_about.set_license (license);
        dialog_about.set_website ("http://www.canol.info");
        dialog_about.set_website_label ("www.canol.info");
        dialog_about.set_logo (logo);
        
        dialog_about.run ();
        
        dialog_about.destroy ();
    }
    
    public int sort_movies (TreeModel tree_model_movies, TreeIter tree_iterator_1, TreeIter tree_iterator_2) {
        string movie_name_1, movie_name_2;
        
        tree_model_movies.get (tree_iterator_1, COLUMNS.NAME, out movie_name_1, -1);
        tree_model_movies.get (tree_iterator_2, COLUMNS.NAME, out movie_name_2, -1);

        if (movie_name_1.down () > movie_name_2.down ()) {
            return 1;
        } else if (movie_name_1.down () < movie_name_2.down ()) {
            return -1;
        }
        
        return 0;
    }

    static int main (string[] args) {
        Gtk.init (ref args);

        try {
            Gtk.Window.set_default_icon_from_file ("icon.png");
        } catch (GLib.Error error) {
            stdout.printf ("Error: %s\n", error.message);
        }

        var movie_archiver = new MovieArchiver ();
        movie_archiver.show_all ();

        Gtk.main ();
        return 0;
    }
}
